//+------------------------------------------------------------------+
//|                     ArrayString.mqh 字符串数组类头文件           |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include "Array.h"   // 引入基础数组类头文件，CArrayString 继承自 CArray
//+------------------------------------------------------------------+
//| CArrayString 类                                                  |
//| 功能：用于管理 string 类型（字符串）的动态数组类                 |
//| 核心特性：支持字符串的动态增删查改，适配 MQL5 字符串比较规则（字典序） |
//| 继承关系：派生自基础数组类 CArray，需注意字符串空值（""）的特殊处理 |
//+------------------------------------------------------------------+
class CArrayString : public CArray
  {
protected:
   string            m_data[];           // 存储字符串的核心数组容器（MQL5 中字符串为引用类型，数组存储字符串引用）

public:
   /**
    * @brief 构造函数：初始化 CArrayString 类实例
    * @details 初始化数组容量（m_data_max）、已存储元素数量（m_data_total）等成员变量，为字符串存储做准备
    */
                     CArrayString(void);

   /**
    * @brief 析构函数：销毁 CArrayString 类实例
    * @details 调用 Shutdown 方法释放数组占用的内存（MQL5 字符串由系统自动管理，无需手动释放内容）
    */
                    ~CArrayString(void);

   //--- 对象类型识别方法
   /**
    * @brief 获取当前数组对象的类型标识
    * @return int - 类型标识，固定返回 TYPE_STRING（表示字符串类型数组）
    */
   virtual int       Type(void) const { return(TYPE_STRING); }

   //--- 文件操作相关方法（字符串需存储长度+内容）
   /**
    * @brief 将数组中的字符串数据写入指定文件（先写字符串长度，再写字符串内容）
    * @details 空字符串（""）会写入长度 0，再跳过内容写入；非空字符串先写长度（int 类型），再写对应长度的字符
    * @param file_handle [in] 已打开的文件句柄（需提前通过 FileOpen 创建，权限包含写入）
    * @return bool - 操作结果：true 表示所有字符串均写入成功，false 表示任一字符串写入失败
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从指定文件读取字符串数据到数组（先读长度，再读对应长度的内容）
    * @details 先读取数组总长度，再逐个读取字符串：先读长度（int 类型），长度为 0 则存入空字符串，否则读对应长度的字符
    * @param file_handle [in] 已打开的文件句柄（需提前通过 FileOpen 创建，权限包含读取）
    * @return bool - 操作结果：true 表示所有字符串均读取成功，false 表示读取失败（如文件格式错误）
    */
   virtual bool      Load(const int file_handle);

   //--- 动态内存管理方法
   /**
    * @brief 为数组预留指定大小的空闲内存空间（存储字符串引用）
    * @details 检查当前剩余空闲空间，不足时按预设步长扩容，减少频繁内存分配的性能开销（字符串引用占用内存小）
    * @param size [in] 需要预留的空闲元素（字符串引用）数量
    * @return bool - 操作结果：true 表示预留成功，false 表示 size≤0 或内存分配失败
    */
   bool              Reserve(const int size);

   /**
    * @brief 调整数组总容量（超出容量的字符串引用会被截断移除）
    * @param size [in] 调整后的数组总容量（包含已存储元素和空闲空间）
    * @return bool - 操作结果：true 表示容量调整成功，false 表示 size<0 或内存分配失败
    */
   bool              Resize(const int size);

   /**
    * @brief 彻底清空数组并释放所有占用的内存
    * @details 重置数组数据、总容量、已存储元素数量等成员变量，将内存归还给系统（字符串内容由 MQL5 自动回收）
    * @return bool - 操作结果：true 表示清理成功，false 表示数组内存释放失败
    */
   bool              Shutdown(void);

   //--- 数组填充相关方法
   /**
    * @brief 向数组末尾添加一个字符串元素
    * @param element [in] 要添加的 string 类型元素（可为空字符串 ""，MQL5 会自动处理空值）
    * @return bool - 操作结果：true 表示添加成功，false 表示内存不足
    */
   bool              Add(const string element);

   /**
    * @brief 将外部 string 数组的所有元素添加到当前数组末尾
    * @param src [in] 外部 string 类型数组（需传入数组引用，确保数组有效）
    * @return bool - 操作结果：true 表示所有元素添加成功，false 表示内存不足
    */
   bool              AddArray(const string &src[]);

   /**
    * @brief 将另一个 CArrayString 实例的所有字符串元素添加到当前数组末尾
    * @param src [in] 指向另一个 CArrayString 实例的指针（需先通过 CheckPointer 验证有效性）
    * @return bool - 操作结果：true 表示所有元素添加成功，false 表示指针无效或内存不足
    */
   bool              AddArray(const CArrayString *src);

   /**
    * @brief 在数组指定索引位置插入一个字符串元素
    * @details 插入位置及后续元素自动后移（字符串引用重排），数组长度加 1
    * @param element [in] 要插入的 string 类型元素（可为空字符串）
    * @param pos [in] 插入位置的索引（从 0 开始，需满足 0≤pos≤当前数组长度）
    * @return bool - 操作结果：true 表示插入成功，false 表示位置无效或内存不足
    */
   bool              Insert(const string element,const int pos);

   /**
    * @brief 将外部 string 数组的所有元素插入到当前数组指定位置
    * @details 插入位置及后续元素自动后移，数组长度增加外部数组的元素个数
    * @param src [in] 外部 string 类型数组（需传入数组引用）
    * @param pos [in] 插入位置的索引（从 0 开始，需满足 0≤pos≤当前数组长度）
    * @return bool - 操作结果：true 表示插入成功，false 表示位置无效或内存不足
    */
   bool              InsertArray(const string &src[],const int pos);

   /**
    * @brief 将另一个 CArrayString 实例的所有元素插入到当前数组指定位置
    * @param src [in] 指向另一个 CArrayString 实例的指针（需验证指针有效性）
    * @param pos [in] 插入位置的索引（从 0 开始，需满足 0≤pos≤当前数组长度）
    * @return bool - 操作结果：true 表示插入成功，false 表示指针无效、位置无效或内存不足
    */
   bool              InsertArray(const CArrayString *src,const int pos);

   /**
    * @brief 用外部 string 数组的内容覆盖当前数组（赋值操作）
    * @details 先清空当前数组所有元素，再将外部数组的字符串完整复制到当前数组
    * @param src [in] 外部 string 类型数组（需传入数组引用）
    * @return bool - 操作结果：true 表示赋值成功，false 表示内存不足
    */
   bool              AssignArray(const string &src[]);

   /**
    * @brief 用另一个 CArrayString 实例的内容覆盖当前数组（赋值操作）
    * @details 先清空当前数组所有元素，再复制源实例的字符串和排序状态到当前数组
    * @param src [in] 指向另一个 CArrayString 实例的指针（需验证指针有效性）
    * @return bool - 操作结果：true 表示赋值成功，false 表示指针无效或内存不足
    */
   bool              AssignArray(const CArrayString *src);

   //--- 数组元素访问方法（空值返回空字符串）
   /**
    * @brief 获取数组指定索引位置的字符串元素
    * @param index [in] 要访问的元素索引（从 0 开始，需满足 0≤index<当前数组长度）
    * @return string - 对应索引的字符串；若索引无效，返回空字符串 ""（MQL5 字符串默认空值）
    */
   string            At(const int index) const;

   /**
    * @brief 重载 [] 运算符，通过索引直接访问数组元素（等价于 At 方法）
    * @param index [in] 要访问的元素索引（从 0 开始，需满足 0≤index<当前数组长度）
    * @return string - 对应索引的字符串；若索引无效，返回空字符串 ""
    */
   string operator[](const int index) const { return(At(index)); }

   //--- 数组元素修改方法
   /**
    * @brief 更新数组指定索引位置的字符串元素
    * @param index [in] 要更新的元素索引（需满足 0≤index<当前数组长度）
    * @param element [in] 新的 string 类型元素（可为空字符串 ""）
    * @return bool - 操作结果：true 表示更新成功，false 表示索引无效
    */
   bool              Update(const int index,const string element);

   /**
    * @brief 将数组指定索引的字符串元素按指定偏移量移动位置
    * @param index [in] 要移动的元素原始索引（需在有效范围内）
    * @param shift [in] 偏移量（正数表示向后移动，负数表示向前移动，需确保移动后位置有效）
    * @return bool - 操作结果：true 表示移动成功，false 表示位置越界或偏移量为 0
    */
   bool              Shift(const int index,const int shift);

   //--- 数组元素删除方法
   /**
    * @brief 删除数组指定索引位置的字符串元素
    * @details 删除后，后续元素自动前移，数组长度减 1（被删除的字符串内容由 MQL5 自动回收）
    * @param index [in] 要删除的元素索引（需满足 0≤index<当前数组长度）
    * @return bool - 操作结果：true 表示删除成功，false 表示索引无效
    */
   bool              Delete(const int index);

   /**
    * @brief 删除数组中指定范围的字符串元素（闭区间 [from, to]）
    * @details 删除后，后续元素自动前移，数组长度减少（to - from + 1）
    * @param from [in] 删除范围的起始索引（需≥0）
    * @param to [in] 删除范围的结束索引（需≥from 且 < 当前数组长度）
    * @return bool - 操作结果：true 表示范围删除成功，false 表示范围无效
    */
   bool              DeleteRange(int from,int to);

   //--- 数组比较方法（按 MQL5 字符串字典序严格比较）
   /**
    * @brief 比较当前数组与外部 string 数组是否完全相等
    * @details 需满足：1. 元素个数相同；2. 对应位置的字符串严格相等（按字典序逐字符比较，区分大小写）
    * @param array [in] 要比较的外部 string 类型数组（需传入数组引用）
    * @return bool - 比较结果：true 表示完全相等，false 表示不相等（长度/字符串不同）
    */
   bool              CompareArray(const string &array[]) const;

   /**
    * @brief 比较当前数组与另一个 CArrayString 实例是否完全相等
    * @details 需满足：1. 元素个数相同；2. 对应位置的字符串严格相等（按 MQL5 字典序比较）
    * @param array [in] 指向要比较的 CArrayString 实例的指针（需验证指针有效性）
    * @return bool - 比较结果：true 表示完全相等，false 表示不相等（指针无效/长度/字符串不同）
    */
   bool              CompareArray(const CArrayString *array) const;

   //--- 有序数组操作方法（按 MQL5 字符串字典序排序/查找）
   /**
    * @brief 向有序数组中插入字符串元素（保持数组字典序特性）
    * @details 需确保数组已排序（m_sort_mode≠-1），插入位置通过字符串字典序比较确定
    * @param element [in] 要插入的 string 类型元素（可为空字符串，空字符串小于所有非空字符串）
    * @return bool - 操作结果：true 表示插入成功且数组保持有序，false 表示数组未排序或内存不足
    */
   bool              InsertSort(const string element);

   /**
    * @brief 在有序数组中查找指定字符串元素的索引（按字典序严格匹配）
    * @param element [in] 要查找的 string 类型元素（空字符串 "" 可正常查找）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序返回 -1
    */
   int               Search(const string element) const;

   /**
    * @brief 在有序数组中查找第一个“大于”指定字符串的元素索引（按字典序）
    * @details MQL5 字符串比较规则：空字符串 < 非空字符串，非空字符串按 ASCII 码逐字符比较（区分大小写）
    * @param element [in] 参考的 string 类型元素
    * @return int - 查找结果：找到时返回对应索引，未找到（如所有元素均≤目标）/数组未排序返回 -1
    */
   int               SearchGreat(const string element) const;

   /**
    * @brief 在有序数组中查找第一个“小于”指定字符串的元素索引（按字典序）
    * @param element [in] 参考的 string 类型元素
    * @return int - 查找结果：找到时返回对应索引，未找到（如所有元素均≥目标）/数组未排序返回 -1
    */
   int               SearchLess(const string element) const;

   /**
    * @brief 在有序数组中查找第一个“大于或等于”指定字符串的元素索引（按字典序）
    * @param element [in] 参考的 string 类型元素
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序返回 -1
    */
   int               SearchGreatOrEqual(const string element) const;

   /**
    * @brief 在有序数组中查找第一个“小于或等于”指定字符串的元素索引（按字典序）
    * @param element [in] 参考的 string 类型元素
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序返回 -1
    */
   int               SearchLessOrEqual(const string element) const;

   /**
    * @brief 在有序数组中查找指定字符串第一次出现的索引（按字典序）
    * @param element [in] 要查找的 string 类型元素（数组中可能存在多个相同字符串）
    * @return int - 查找结果：找到时返回第一次出现的索引，未找到/数组未排序返回 -1
    */
   int               SearchFirst(const string element) const;

   /**
    * @brief 在有序数组中查找指定字符串最后一次出现的索引（按字典序）
    * @param element [in] 要查找的 string 类型元素（数组中可能存在多个相同字符串）
    * @return int - 查找结果：找到时返回最后一次出现的索引，未找到/数组未排序返回 -1
    */
   int               SearchLast(const string element) const;

   /**
    * @brief 对数组进行线性查找（遍历数组，适用于无序数组，按字典序严格匹配）
    * @param element [in] 要查找的 string 类型元素（空字符串 "" 可正常查找）
    * @return int - 查找结果：找到时返回第一个匹配元素的索引，未找到返回 -1
    */
   int               SearchLinear(const string element) const;

protected:
   /**
    * @brief 快速排序算法：对数组指定范围元素按字典序排序（内部使用，不对外暴露）
    * @param beg [in] 排序范围的起始索引（需≥0）
    * @param end [in] 排序范围的结束索引（需≥beg 且 < 当前数组容量）
    * @param mode [in] 排序模式（默认 0，通常表示升序，具体逻辑继承自父类 CArray）
    */
   virtual void      QuickSort(int beg,int end,const int mode=0);

   /**
    * @brief 快速查找算法：在有序数组中按字典序定位字符串位置（内部使用，为 Search 系列提供支持）
    * @details 基于二分法，通过 MQL5 字符串比较规则判断大小关系
    * @param element [in] 要查找的 string 类型元素
    * @return int - 查找的中间位置索引（若找到则为匹配元素索引，未找到则为最后比较的中间位置）
    */
   int               QuickSearch(const string element) const;

   /**
    * @brief 数组内部内存移动：将指定范围的字符串引用从源位置复制到目标位置（内部使用）
    * @details 用于插入、删除等操作时的元素位置调整，复制的是字符串引用（非内容拷贝，效率高）
    * @param dest [in] 目标位置的起始索引（需≥0）
    * @param src [in] 源位置的起始索引（需≥0）
    * @param count [in] 要移动的引用个数（需满足 src + count ≤ 当前数组长度）
    * @return int - 操作结果：成功返回目标位置起始索引，失败返回 -1
    */
   int               MemMove(const int dest,const int src,int count);
  };
//+------------------------------------------------------------------+